package com.jsg.sl651.constant;

import com.jsg.sl651.entity.data.Element;
import com.jsg.sl651.entity.data.Identifier;
import com.jsg.sl651.enums.CodingElementEnum;
import com.jsg.sl651.enums.CommunicationMessageType;
import com.jsg.sl651.enums.DataDefinitionType;
import com.jsg.sl651.enums.DefinitionType;
import com.jsg.sl651.message.parser.Parser;
import com.jsg.sl651.message.parser.ParserFactory;
import com.jsg.sl651.util.ByteUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

/**
 * 编码要素及标识符汇总表
 */
@Slf4j
public final class EncodingElementIdentifier {

    private static final Map<String, EncodingElement> HEX = new HashMap<>();
    private static final Map<String, EncodingElement> ASCII = new HashMap<>();
    private static final EncodingElement UNKNOWN = new EncodingElement(new byte[0], new byte[0], DefinitionType.CUSTOMIZE, "未知属性", "未知属性", DataDefinitionType.HEX, 0, null,null);

    static {
        // todo 去注册文档中定义的编码要素及标识符
        CodingElementEnum[] values = CodingElementEnum.values();
        for (CodingElementEnum value : values) {
            register(value.getHexBytes(), value.getAsciiBytes(), value.getName(), value.getDesc(), value.getDataDefinitionType(), value.getPrecision(), value.getUnit(),value.getParser());
            log.info("注册编码要素：{}", value.getName());
        }
    }


    public static void register(final byte[] hexBytes, final byte[] asciiBytes,
                                final String name,
                                final String desc,
                                final DataDefinitionType dataDefinitionType,
                                final int precision,
                                final String unit,Class<? extends Parser<?>> parser) {
        EncodingElement encodingElement = new EncodingElement(hexBytes, asciiBytes, DefinitionType.CUSTOMIZE, name, desc, dataDefinitionType, precision, unit,parser);
        String hex = encodingElement.getHex().getHex();
        if (HEX.containsKey(hex)) {
            log.warn("重复注册hex标识符：{},这个操作将会替代原始的处理器，请知悉", hex);
        }
        HEX.put(hex, encodingElement);
        String hex1 = encodingElement.getAscii().getHex();
        if (ASCII.containsKey(hex1)) {
            log.warn("重复注册ascii标识符：{},这个操作将会替代原始的处理器，请知悉", hex1);
        }
        ASCII.put(hex1, encodingElement);
    }



    public static <T> Element<T> parser(CommunicationMessageType type, byte[] key, byte[] bytes) {
        return parser(type, ByteUtil.toHex(key), bytes);
    }

    public static <T> Element<T> parser(CommunicationMessageType type, Identifier identifier) {
        return parser(type, identifier.getKeyHex(), identifier.getData());
    }

    /**
     * 根据通信消息类型和标识符字节解析字节数组为数据对象。
     *
     * <p>方法核心</p>
     * <ul>
     *     <li>根据传入的通信消息类型（HEX 或 ASCII）从对应的映射表中查找标识符定义。</li>
     *     <li>如果找不到对应的标识符定义，抛出 RuntimeException。</li>
     *     <li>使用找到的标识符定义中的解析器类解析字节数组。</li>
     * </ul>
     *
     * @param type  通信消息类型，枚举值 {@link CommunicationMessageType}
     * @param keyHex   标识符字节数组
     * @param bytes 待解析的字节数组
     * @return 解析成功后生成的数据对象 {@link Element}
     */
    public static <T> Element<T> parser(CommunicationMessageType type, String keyHex, byte[] bytes) {
        EncodingElement encodingElement = null;
        if (type == CommunicationMessageType.HEX) {
            encodingElement = HEX.get(keyHex);
        } else if (type == CommunicationMessageType.ASCII) {
            encodingElement = ASCII.get(keyHex);
        }
        if (encodingElement == null) {
            return (Element<T>) new Element<>(bytes, bytes, UNKNOWN);
        }
        // 处理数据
        return (Element<T>) ParserFactory.parser(encodingElement, type, bytes);
    }


    /**
     *  标识符来源
     */

    // 具体标识属性
    @Getter
    @AllArgsConstructor
    public static class EncodingElement {
        // hex 模式下标识符
        private final DefinitionElement hex;
        // ascii 模式下标识符
        private final DefinitionElement ascii;
        // 标识符类型[自定义 还是 定义]
        private final DefinitionType definitionType;
        // 数据名
        private final String name;
        // 数据表述
        private final String desc;
        // 报文定义类型
        private final DataDefinitionType dataDefinitionType;
        // 数据精度
        private final int precision;
        // 数据单位
        private final String unit;

        private final Class<? extends Parser<?>> parser;

        public static EncodingElement document(final byte[] hexBytes, final byte[] asciiBytes,
                                           final String name,
                                           final String desc,
                                           final DataDefinitionType dataDefinitionType,
                                           final int precision,
                                           final String unit,Class<? extends Parser<?>> parser) {
            return new EncodingElement(hexBytes, asciiBytes, DefinitionType.DOCUMENT_DEFINITION, name, desc, dataDefinitionType, precision, unit, parser);
        }

        public static EncodingElement custom(final byte[] hexBytes, final byte[] asciiBytes,
                                           final String name,
                                           final String desc,
                                           final DataDefinitionType dataDefinitionType,
                                           final int precision,
                                           final String unit,Class<? extends Parser<?>> parser) {
            return new EncodingElement(hexBytes, asciiBytes, DefinitionType.CUSTOMIZE, name, desc, dataDefinitionType, precision, unit,parser);
        }

        public EncodingElement(final byte[] hexBytes, final byte[] asciiBytes,
                               final DefinitionType definitionType,
                               final String name,
                               final String desc,
                               final DataDefinitionType dataDefinitionType,
                               final int precision,
                               final String unit,Class<? extends Parser<?>> parser) {
            this.hex = new DefinitionElement(hexBytes);
            this.ascii = new DefinitionElement(asciiBytes);
            this.definitionType = definitionType;
            this.name = name;
            this.desc = desc;
            this.dataDefinitionType = dataDefinitionType;
            this.precision = precision;
            this.unit = unit;
            this.parser = parser;
        }

    }

    // HEX 或者是 ASCII报文定义
    @Getter
    public static class DefinitionElement {
        // 标志符号Hex
        private final String hex;
        // 标识符字节码
        private final byte[] bytes;
        public DefinitionElement(final byte[] bytes) {
            this.bytes = bytes;
            this.hex = ByteUtil.toHex(bytes);
        }
    }

}
